package com.example.lotterysystem.service.activitystatus.impl;

import com.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.service.ActivityService;
import com.example.lotterysystem.service.activitystatus.ActivityStatusManager;
import com.example.lotterysystem.service.activitystatus.operater.AbstractActivityOperator;
import com.example.lotterysystem.service.dto.ConvertActivityStatusDTO;
import com.example.lotterysystem.service.impl.DrawPrizeServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Component
public class ActivityStatusManagerImpl implements ActivityStatusManager {
    // 日志
    private static final Logger logger = LoggerFactory.getLogger(ActivityStatusManagerImpl.class);

    @Autowired
    // 这里使用 @Autowired 就会进行注入 实现AbstractActivityOperator这个抽象类的具体对象
    // 这里的 String 就是对象对应的名称
    private final Map<String, AbstractActivityOperator> operatorMap = new HashMap<>();

    @Autowired
    private ActivityService activityService;

    /**
     * 更新状态前置
     * @param convertActivityStatusDTO
     */
    @Override
    // 保证事务的一致性
    @Transactional(rollbackFor = Exception.class)
    public void handlerEvent(ConvertActivityStatusDTO convertActivityStatusDTO) {
        // 1、活动状态扭转存在依赖性，导致代码维护性差，活动扭转需要奖品都结束，才能进行扭转
        // 2、状态扭转条件可能存在需要扩展的情况，如果按照下述的写法呢，就存在扩展性差，维护性差的情况
        // 3、这样会使代码的灵活性、维护性、可扩展性变差
        // 解决方法: 责任链设计模式(解决1) 策略模式(解决2)

        // 使用 Map<String, AbstractActivityOperator> 进行管理 是 奖品还是人员 还是活动 进行的扭转状态的操作
        if (CollectionUtils.isEmpty(operatorMap)) {
            logger.warn("operatorMap 为空!");
            return;
        }
        Boolean update = false;
        // 将 operatorMap 初始化到 currMap 中，使用currMap 进行遍历处理
        Map<String,AbstractActivityOperator> currMap = new HashMap<>(operatorMap);

        //责任链模式，定义先处理什么后处理什么，之后参数传递一个标识，为了确定 策略模式中的 map中谁可以执行
        // 先处理: 奖品、人员
        // 这里的1 代表先处理
        update =  processConvertStatus(convertActivityStatusDTO,currMap,1);

        // 后处理: 活动
        // 这里的2 代表后处理
        if (update == true) {
            // 如果这里为真的话，说明 1 已经进行处理了，那么为了防止 2 可能返回 false，那么这里不能进行赋值
            processConvertStatus(convertActivityStatusDTO,currMap,2);
        }else {
            // 这里 1 没有进行修改，那么看看 2 是否可以进行修改，能否返回true
            update =  processConvertStatus(convertActivityStatusDTO,currMap,2);
        }

        // 更新缓存
        if (update == true) {
            activityService.cacheActivity(convertActivityStatusDTO.getActivityId());
        }
    }

    /**
     * 回滚状态
     * @param convertActivityStatusDTO
     */
    @Override
    public void rollbackHandlerEvent(ConvertActivityStatusDTO convertActivityStatusDTO) {
        // operatorMap 中存在所有的要修改的状态
        // 活动状态是否需要回滚？？是一定需要的
        // 原因: 在 奖品、人员 进行修改成 INIT 的时候，说明这个活动没有完成，所以需要进行修改
        // 所以直接进行遍历这个 operatorMap 即可
        for (AbstractActivityOperator abstractActivityOperator : operatorMap.values()) {
            abstractActivityOperator.convert(convertActivityStatusDTO);
        }

        // 更新缓存
        activityService.cacheActivity(convertActivityStatusDTO.getActivityId());
    }

    /**
     * 进行处理状态转换
     * @param convertActivityStatusDTO
     * @param currMap
     * @param sequence
     * @return
     */
    private Boolean processConvertStatus(ConvertActivityStatusDTO convertActivityStatusDTO,
                                         Map<String, AbstractActivityOperator> currMap,
                                         int sequence) {
        Boolean update = false;
        // 使用迭代器 遍历 currMap
        Iterator<Map.Entry<String, AbstractActivityOperator>> iterator = currMap.entrySet().iterator();
        while(iterator.hasNext()) {
            AbstractActivityOperator operator = iterator.next().getValue();
            // 判断 operator 是否需要转换
            if (operator.sequence() != sequence
                    || !operator.needConvert(convertActivityStatusDTO)) {
                // 不需要转换，或者是 不在当前sequence 下进行转换
                continue;
            }

            // 需要转换，转换操作
            if (!operator.convert(convertActivityStatusDTO)) {
                logger.error("{}状态转换失败！",operator.getClass().getName());
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_STATUS_CONVERT_ERROR);
            }

            // 转换成功之后，将转换成功的对象从currMap中删除
            iterator.remove();
            update = true;
        }
        return update;
    }
}
